package pub.tbc.api.handler.old;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;
import pub.tbc.api.invoker.Invoker;
import pub.tbc.api.invoker.InvokerFactory;
import pub.tbc.api.invoker.protocol.http.NettyHttpUtil;


/**
 * netty处理调最后一环，请求其它系统；
 * 需要：协议转换组件、具体协议的请求转发组件
 *
 * @author tbc on 2017/3/3 13:10:53.
 */
@Slf4j
public class InvokerHandler4 extends SimpleChannelInboundHandler<FullHttpRequest> {
    // 具体的的调用器应该按配置生成（约定默认值），交由专门的工厂处理
    private Invoker invoker = InvokerFactory.getInvoker();
    private Channel outboundChannel;

    static void closeOnFlush(Channel ch) {
        if (ch.isActive()) {
            ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest msg) throws Exception {
        final Channel inboundChannel = ctx.channel();

//        String host = "211.157.179.221";
//        int port = 22100;

        String host = "it";
        int port = 8888;

        Bootstrap b = new Bootstrap();
        b.group(NettyHttpUtil.getClientEventLoopGroup())     // use inboundChannel thread
                .channel(ctx.channel().getClass())
                .handler(new BackendHandlerInitializer(inboundChannel));

        ChannelFuture f = b.connect(host, port);
        outboundChannel = f.channel();
        msg.retain();// 当客户端代码中需要保持一个该对象的引用时，调用此方法将计数加1
        ChannelFuture channelFuture = f.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
                if (future.isSuccess()) {
                    FullHttpRequest req = new DefaultFullHttpRequest(
                            HttpVersion.HTTP_1_1,
                            msg.method(),
//                            "/yijiajiao-wares/basic/subjects"
                            msg.uri()
                    );
                    HttpHeaders reqHeaders = req.headers();
                    msg.headers().forEach(header -> {
                        if (header.getKey().equalsIgnoreCase("host"))
//                            req.headers().set("Host", "211.157.179.221:22100");
                            req.headers().set("Host", "127.0.0.1:8888");
                        else
                            req.headers().set(header.getKey(), header.getValue());
                    });
                    log.debug("send request : {}", req);


                    outboundChannel.writeAndFlush(req);
                } else {
                    inboundChannel.close();
                }
            }
        });
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext context, Throwable cause) {
        log.error("发生异常： {}", cause.getMessage());
        context.close();
        context.fireChannelRead(cause);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println("[断开连接]channelInactive...");
    }

    @Override
    public void channelActive(ChannelHandlerContext context) throws Exception {
        System.out.println("[建立连接]channelActive...");
        System.out.println("FrontEnd Handler is Active!");
        super.channelActive(context);
    }

    private static class BackendHandlerInitializer extends ChannelInitializer<SocketChannel> {

        final Channel inboundChannel;

        public BackendHandlerInitializer(Channel inboundChannel) {
            this.inboundChannel = inboundChannel;
        }

        @Override
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new HttpClientCodec())
                    .addLast(new HttpObjectAggregator(1024 * 1024))
                    .addLast(new HttpBackendHandler(inboundChannel));
        }
    }

    private static class HttpBackendHandler extends SimpleChannelInboundHandler<FullHttpResponse> {

        private final Channel inboundChannel;

        public HttpBackendHandler(Channel inboundChannel) {
            this.inboundChannel = inboundChannel;
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("Backend Handler is Active!");
            super.channelActive(ctx);
        }

        @Override
        public void channelRead0(final ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
            log.info("收到第三方响应: {}", msg);
            inboundChannel.writeAndFlush(msg.retain()).addListener(new ChannelFutureListener() {
                public void operationComplete(ChannelFuture future) throws Exception {
                    log.debug(".......................................");
                    if (!future.isSuccess()) {
                        future.channel().close();
                    }
                }
            });
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            System.out.println("[代理连接断开]Backend Handler destroyed!");
            NettyHttpUtil.closeOnFlush(inboundChannel);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            NettyHttpUtil.closeOnFlush(ctx.channel());
        }
    }


}
